using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Collections.Specialized;
using System.IO;
using System.Xml.Xsl;
using System.Text.RegularExpressions;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using System.Xml.XPath;
using LB.Generics;
using ExtraClub.Domain.Entity;
using ExtraClub.Domain.Framework;

namespace ExtraClub.Domain {
    public partial class SiteManager {
        #region Data
        HttpContext Context = null;
        string XMLPath = null;
        static readonly SiteManager instance = new SiteManager();
        #endregion

        #region Instance Creation
        private SiteManager() {
            Context = HttpContext.Current;
            XMLPath = Context.Server.MapPath(Constants.SITE_XML_LOCATION);
        }
        public static SiteManager Instance {
            get { return instance; }
        }
        #endregion

        private XDocument GetSiteData() {
            Cache Cache = HttpRuntime.Cache;
            string cachKey = this.GetType().ToString();
            XDocument doc = (XDocument)Cache[cachKey];

            if (doc == null) {
                doc = XDocument.Load(XMLPath);
                PutIntoCach(cachKey, doc);
            }
            return doc;
        }

        #region Site Getters

        public static string GetDefaultLanguage() {
            XDocument doc = (XDocument)Instance.GetSiteData();
            var q = from a
                    in doc
                    .Element("site")
                    .Elements("langs")
                    select (string)a.Attribute("default");

            return q.Take(1).Single<string>();
        }
        /// <summary>
        /// Returns ID of a given Url
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetItemIdByUrl(string url) {
            XDocument doc = (XDocument)Instance.GetSiteData();
            var q = from a in doc.Elements("site").Elements("layout").Elements("item")
                    where a.Attribute("url") != null && a.Attribute("url").Value == url
                    select (string)a.Attribute("id");

            return q.Take(1).Single<string>();
        }

        /// <summary>
        /// Returns Url to Home Page
        /// </summary>
        /// <returns></returns>
        public static string GetHomePage() {
            XDocument doc = (XDocument)Instance.GetSiteData();
            var q = from a in doc.Elements("site").Elements("layout").Elements("item")
                    where a.Attribute("url") != null
                    select (string)a.Attribute("url");

            return q.Take(1).Single<string>();
        }


        /// <summary>
        /// Builds a Web Page Object by given Url ("some-page") 
        /// Url of the page relates to the Page ID which in its turn is the Model Page name and a part
        /// of the path to the module
        /// 
        /// The function sets by a SiteContext's setter in BasePage OnLoad 
        /// </summary>
        /// <returns></returns>
        internal static WebPage BuildWebPageByUrl(string url) {
            XDocument doc = (XDocument)Instance.GetSiteData();
            var q = from a in doc
                        .Element("site")
                        .Element("layout")
                        .Elements("item")
                    where a.Attribute("url") != null && a.Attribute("url").Value == url
                    select a;

            XElement p = q.Take(1).Single();

            WebPage page = new WebPage();
            page.Id = p.Attribute("id").Value;
            page.Url = p.Attribute("url").Value;

            foreach (var el in p.Elements("lang").Where(delegate(XElement item) { return item.Attribute("id").Value == SiteContext.Current.Language; })) {
                page.Title = el.Element("title").Value;
                page.Description = el.Element("desc").Value;
            }
            return page;
        }


        ///// <summary>
        ///// Returns list of selected menu. Now only plain list 
        ///// TODO: create hearchal list
        ///// </summary>
        ///// <param name="id"></param>
        ///// <returns></returns>
        //public static MenuCollection GetMenuByItemId(string id) {
        //    if (string.IsNullOrEmpty(id)) return null;

        //    MenuCollection menu = null;
        //    XDocument doc = (XDocument)Instance.GetSiteData();
        //    var q =
        //        from a in doc.Elements("site").Elements("layout").Elements("item")
        //        where a.Attribute("url") != null
        //        from b in doc.Elements("site")
        //                .Elements("menus")
        //                .Elements("item").Where(delegate(XElement item) { return item.Attribute("id").Value == id; })
        //                .Elements("items")
        //                .Elements("item")
        //        where a.Attribute("id").Value == b.Attribute("id").Value
        //        select a;

        //    if (q.Count() > 0) {
        //        menu = new MenuCollection();
        //        foreach (var item in q) {
        //            Menu m = new Menu();
        //            m.Id = item.Attribute("id").Value;
        //            m.Title = item.Attribute("menu-title").Value;

        //            string entityUrl = SiteContext.Current.Page.Url;
        //            m.Url = item.Attribute("url").Value + (string.IsNullOrEmpty(entityUrl) ? "" : "/" + entityUrl) + ".aspx";
        //            menu.Add(m);
        //        }
        //    }
        //    return menu;
        //}

        public static Menu BuildMainMenuByUrl(string url) {
            if (string.IsNullOrEmpty(url)) return null;

            XDocument doc = (XDocument)Instance.GetSiteData();
            var q =
                from a in doc.Element("site").Element("layout").Elements("item")
                where a.Attribute("url") != null && a.Attribute("url").Value == url
                from b in doc
                        .Element("site")
                        .Element("menus")
                        .Elements("item").Where(delegate(XElement item) { return item.Attribute("id").Value == a.Attribute("id").Value; })
                        .Elements("items").Elements("item")
                select b;

            Menu menu = null;
            if (q.Count() > 0) {
                menu = new Menu();
                menu.Items = new List<MenuItem>();
                XElement[] a = q.ToArray<XElement>();

                Test(menu, a, url);
            }
            return menu;
        }
        private static void Test(Menu menu, XElement[] q, string url) {
            
            foreach (var item in q) {
                MenuItem mi = new MenuItem();
                mi.Id = item.Attribute("id").Value;
                mi.Title = item.Element("lang").Value;

                string param = "view";
                string view = item.Attribute("view").Value;
                NameValueCollection Q = HttpContext.Current.Request.QueryString;
                if (Q.Count > 0 && Q[param] != null) {
                    mi.Current = view == Q[param];
                } else {
                    mi.Current = menu.Items.Count == 0 ? true : false;
                }

                if (mi.Current) {
                    menu.CurrentItem = mi.Id;
                }
                mi.Url = string.Format("{0}.aspx?{1}={2}", url, param, item.Attribute("view").Value);

                menu.Items.Add(mi);
            }
        }
        #endregion


        #region Routines
        private void PutIntoCach(string key, object value) {
            CacheDependency dp = new CacheDependency(XMLPath);
            HttpRuntime.Cache.Add(key, value, dp, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(OnRemoved));
        }

        public void OnRemoved(String key, object value, CacheItemRemovedReason removedReason) {
            if (removedReason == CacheItemRemovedReason.DependencyChanged) {
                PutIntoCach(key, GetSiteData());
            }
        }
        #endregion
    }
}
